/**
 *
 */
package com.zx.cloud.util;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author gn
 */
public class URLUtils {

	public static void main(String[] args) {
		Map<String, List<String>> map = getParamters("https://github.com/search?l=Java&p=4&q=URLUtil&ref=cmdform&type=Code,demo&utf8=");
		for (String name : map.keySet()) {
			System.out.print("name=[" + name);
			List<String> values = map.get(name);
			for (String v : values) {
				System.out.print("," + v);
			}
			System.out.print("]\n");
		}
	}

	public static String append(final CharSequence url, final Map<?, ?> params) {
		final String baseUrl = url.toString();
		if (params == null || params.isEmpty()) {
			return baseUrl;
		}
		final StringBuilder result = new StringBuilder(baseUrl);
		if (baseUrl.indexOf(':') + 2 == baseUrl.lastIndexOf('/')) {
			result.append('/');
		}
		final int queryStart = baseUrl.indexOf('?');
		final int lastChar = result.length() - 1;
		if (queryStart == -1) {
			result.append('?');
		} else if (queryStart < lastChar && baseUrl.charAt(lastChar) != '&') {
			result.append('&');
		}
		Entry<?, ?> entry;
		Object value;
		Iterator<?> iterator = params.entrySet().iterator();
		entry = (Entry<?, ?>) iterator.next();
		result.append(entry.getKey().toString());
		result.append('=');
		value = entry.getValue();
		if (value != null) {
			result.append(value);
		}
		while (iterator.hasNext()) {
			result.append('&');
			entry = (Entry<?, ?>) iterator.next();
			result.append(entry.getKey().toString());
			result.append('=');
			value = entry.getValue();
			if (value != null) {
				result.append(value);
			}
		}
		return result.toString();
	}

	public static Map<String, String> getHeaderValues(final String header) {
		if (header == null || header.length() == 0) {
			return Collections.emptyMap();
		}
		final int headerLength = header.length();
		int start = header.indexOf(';') + 1;
		if (start == 0 || start == headerLength) {
			return Collections.emptyMap();
		}
		int end = header.indexOf(';', start);
		if (end == -1) {
			end = headerLength;
		}
		Map<String, String> params = new LinkedHashMap<String, String>();
		while (start < end) {
			int nameEnd = header.indexOf('=', start);
			if (nameEnd != -1 && nameEnd < end) {
				String name = header.substring(start, nameEnd).trim();
				if (name.length() > 0) {
					String value = header.substring(nameEnd + 1, end).trim();
					int length = value.length();
					if (length != 0) {
						if (length > 2 && '"' == value.charAt(0) && '"' == value.charAt(length - 1)) {
							params.put(name, value.substring(1, length - 1));
						} else {
							params.put(name, value);
						}
					}
				}
			}
			start = end + 1;
			end = header.indexOf(';', start);
			if (end == -1) {
				end = headerLength;
			}
		}
		return params;
	}

	public static Map<String, List<String>> getParamters(final String url) {
		if (url == null || url.length() == 0) {
			return Collections.emptyMap();
		}
		int start = url.indexOf("?") + 1;
		if (start == 0) {
			return Collections.emptyMap();
		}
		Map<String, List<String>> params = new HashMap<String, List<String>>();
		String queryUrl = url.substring(start);
		String[] pArr = queryUrl.split("[&]");
		if (pArr.length > 1) {
			for (String a : pArr) {
				String[] nv = a.split("[=]");
				if (nv.length > 1) {
					String name = nv[0];
					List<String> values = new ArrayList<String>();
					String value = nv[1];
					if (value != null && !value.equals("") && value.length() >= 1) {
						if (value.contains(",")) {
							String[] valueArr = value.split("[,]");
							values.addAll(Arrays.asList(valueArr));
						} else {
							values.add(value.trim());
						}
						params.put(name.trim(), values);
					}
				}
			}
		}
		return params;
	}

	public enum Protocol {
		HTTP(80), HTTPS(443);
		private int port;

		Protocol(int port) {
			this.port = port;
		}

		public int getPort() {
			return port;
		}
	}

	public static String setBaseUrl(String url) {
		Pattern pattern = Pattern.compile("([^:]+)://([^:]+)(:([0-9]+))?");
		Matcher matcher = pattern.matcher(url);
		if (!matcher.matches()) {
			throw new IllegalArgumentException("Invalid url: " + url);
		}
		String scheme = matcher.group(1);
		String host = matcher.group(2);
		int _port = 0;
		String port = matcher.group(4);
		if (port != null) {
			_port = Integer.valueOf(port);
		} else {
			_port = Protocol.valueOf(scheme.toUpperCase()).getPort();
		}
		return scheme + "://" + host + ":" + _port;
	}

	public static String getQueryString(Map<String, List<String>> params) {
		String result = null;
		if (!params.isEmpty()) {
			StringBuilder builder = new StringBuilder();
			for (Iterator<Entry<String, List<String>>> i = params.entrySet().iterator(); i.hasNext();) {
				Entry<String, List<String>> param = i.next();
				String name = param.getKey();
				for (Iterator<String> j = param.getValue().iterator(); j.hasNext();) {
					String value = j.next();
					builder.append(name);
					if (value != null) {
						builder.append('=');
						try {
							builder.append(URLEncoder.encode(value, "UTF-8"));
						} catch (UnsupportedEncodingException e) {
							throw new IllegalStateException(e);
						}
					}
					if (j.hasNext()) {
						builder.append('&');
					}
				}
				if (i.hasNext()) {
					builder.append('&');
				}
			}
			result = builder.toString();
		}
		return result;
	}

	private static BitSet dontNeedEncoding;

	static {
		dontNeedEncoding = new BitSet(256);
		int i;
		for (i = 'a'; i <= 'z'; i++) {
			dontNeedEncoding.set(i);
		}
		for (i = 'A'; i <= 'Z'; i++) {
			dontNeedEncoding.set(i);
		}
		for (i = '0'; i <= '9'; i++) {
			dontNeedEncoding.set(i);
		}
		dontNeedEncoding.set(' ');
		dontNeedEncoding.set('-');
		dontNeedEncoding.set('_');
		dontNeedEncoding.set('.');
		dontNeedEncoding.set('*');
		dontNeedEncoding.set('+');
		dontNeedEncoding.set('%');
	}

	public static final boolean isURLEncoded(String str) {
		if (str == null || "".equals(str)) {
			return false;
		}
		char[] chars = str.toCharArray();
		boolean containsPercent = false;
		for (char c : chars) {
			if (Character.isWhitespace(c)) {
				return false;
			}
			if (!dontNeedEncoding.get(c)) {
				return false;
			}
			if (c == '%') {
				containsPercent = true;
			}
		}
		if (!containsPercent) {
			return false;
		}
		return true;
	}

	public static final String encodeURL(String str) {
		try {
			return URLEncoder.encode(str, "utf-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	public static final String decodeURL(String str) {
		try {
			return URLDecoder.decode(str, "utf-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	public static boolean isDefaultPort(URI uri) {
		String scheme = uri.getScheme().toLowerCase();
		int port = uri.getPort();
		return port <= 0 || (port == 80 && scheme.equals("http")) || (port == 443 && scheme.equals("https"));
	}

	public static String encodeUrl(String value, boolean path, boolean canonical) {
		if (value == null || value.equals("")) {
			return "";
		}
		String encoded;
		try {
			encoded = URLEncoder.encode(value, "UTF-8");
		} catch (UnsupportedEncodingException ex) {
			throw new IllegalStateException("Unable to UTF-8 encode url string component [" + value + "]", ex);
		}
		if (canonical) {
			encoded = encoded.replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
			if (path) {
				encoded = encoded.replace("%2F", "/");
			}
		}
		return encoded;
	}

}